﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;

namespace EasyTest {

    /// <summary>
    /// Object representing the Browser type used in the test.
    /// </summary>
    public class Browser {

        public static TestContext TestContext { get; set; }
        /// <summary>
        /// Get and set the name of the browser.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Get and set the WebDriver.
        /// </summary>
        public static IWebDriver Driver { get; set; }

        /// <summary>
        /// Get and set the Focus that is active.
        /// </summary>
        public static Focus ActiveFocus { get; set; }

        /// <summary>
        /// Get and set the number of seconds for the browser object to wait.
        /// </summary>
        public static TimeSpan MaxWait = new TimeSpan(0, 0, 0, 30);

        /// <summary>
        /// Get and set the directory where the drivers are located.
        /// </summary>
        public static string DriversDirectory { get; set; }

        /// <summary>
        /// Set up the browser and set the default DriversDirectory.
        /// </summary>
        private Browser() {
            DriversDirectory = "C:\\WebDrivers\\";
        }

        /// <summary>
        /// If Debug Mode is set, will capture details about every page hit in the test. Used for trying to debug testing. 
        /// </summary>
        public static bool DebugMode = true;
        public static List<DriverInfo> DriverInfoList = new List<DriverInfo>(); 
        /// <summary>
        /// Set the browser object to represent Intenet Explorer and set the set the starting URL.
        /// </summary>
        /// <param name="startingUrl">The starting URL to set the browser to.</param>
        public static void SetToIe(string startingUrl) {
            Driver = new InternetExplorerDriver("C:\\WebDrivers\\");
            SetDefault(startingUrl);
        }
        public static void SetToIe(string startingUrl, TestContext testContext, bool killOpenBrowser)
        {
            TestContext = testContext;
            if(killOpenBrowser)
                Kill("iexplore");
            SetToIe(startingUrl);


        }
        /// <summary>
        /// Set the browser object to represent Firefox and set the set the starting URL.
        /// </summary>
        /// <param name="startingUrl">The starting URL to set the browser to.</param>
        public static void SetToFirefox(string startingUrl) {
            Driver = new FirefoxDriver();
            SetDefault(startingUrl);
            SetTimeOut();
        }

        /// <summary>
        /// Set the browser object to represent Chrome and set the set the starting URL.
        /// </summary>
        /// <param name="startingUrl">The starting URL to set the browser to.</param>
        public static void SetToChrome(string startingUrl) {
            Driver = new ChromeDriver("C:\\Drivers\\");
            SetDefault(startingUrl);
            SetTimeOut();
        }

        /// <summary>
        /// Set set the starting URL for the current browser.
        /// </summary>
        /// <param name="startingUrl">The starting URL to set the browser to.</param>
        public static void SetDefault(string startingUrl) {
            Driver.Navigate().GoToUrl(startingUrl);
            SetTimeOut();
        }

        /// <summary>
        /// Close the current browser session.
        /// </summary>
        public static void Close() {
            Close(false);
        }

        /// <summary>
        /// Close the current browser session.
        /// </summary>
        /// <param name="killBrowser">True/False whether or not to close all current processes for the same browser type.</param>
        public static void Close(bool killBrowser) {
            Driver.Quit();
            KillProcesses(killBrowser);
        }

        /// <summary>
        /// Kill the current browser session only.
        /// </summary>
        public static void KillProcesses() {
            KillProcesses(false);
        }

        /// <summary>
        /// Kill the current browser session and pass whether or not to kill all broswer sessions for the same browser type.
        /// </summary>
        /// <param name="killBrowser">True/False whether or not to close all current processes for the same browser type.</param>
        public static void KillProcesses(bool killBrowser) {
            Kill(new string[] { "IEDriverServer", "chromedriver" });
            if (killBrowser) {
                if (Driver.GetType() == typeof(InternetExplorerDriver))
                    Kill("iexplore");
                if (Driver.GetType() == typeof(FirefoxDriver))
                    Kill("firefox");
                if (Driver.GetType() == typeof(ChromeDriver))
                    Kill("chrome");
            }
        }

        /// <summary>
        /// Kill the process matching the name of the process passed.
        /// </summary>
        /// <param name="process">Text name of the process to kill</param>
        public static void Kill(string process) {
            Kill(new string[] { process });
        }

        /// <summary>
        /// Kill the processes matching the array of names of the processes passed.
        /// </summary>
        /// <param name="process">Array of strings representing the names of the processes to kill</param>
        private static void Kill(string[] processes) {
            foreach (Process process in Process.GetProcesses()) {
                if (processes.Contains(process.ProcessName))
                    process.Kill();
            }
        }

        /// <summary>
        /// Create a new browser window for the page object passed.
        /// </summary>
        /// <param name="page">Page object to load in the new browser window.</param>
        public static void NewWindow(Page page) {
            page.Go();
            NewWindow(Browser.Driver.Url);

        }

        /// <summary>
        /// Create a new browser window for the page object passed.
        /// </summary>
        /// <param name="url">String with the site address to load in a new browser window.</param>
        public static void NewWindow(string url) {
            try {
                foreach (string windowHandle in Driver.WindowHandles) {
                    Driver.SwitchTo().Window(windowHandle);
                    if (Driver.Url == url) {
                        Driver.Close();
                        break;
                    }
                }
                Driver.SwitchTo().Window(Driver.WindowHandles[1]);

                IJavaScriptExecutor jscript = Browser.Driver as IJavaScriptExecutor;
                jscript.ExecuteScript("window.open('" + url + "')");
            } 
            catch (Exception e)
            {
                throw new System.Exception("Unable to create new window:" + url);
            }
        }
        public static void SetTimeOut()
        {
            Driver.Manage().Timeouts().ImplicitlyWait(MaxWait);
            Driver.Manage().Timeouts().SetPageLoadTimeout(MaxWait);
            Driver.Manage().Timeouts().SetScriptTimeout(MaxWait);
        }
        public static void LogDriverInfo()
        {
            if(Browser.DebugMode)
                Browser.DriverInfoList.Add(EasyTest.DriverInfo.GetInfo(null));
            
        }
    }

}
